
    window.onload = async () => {
    const env = {
        serviceUrl: "https://vjmap.com/server/api/v1",
        accessToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6MiwiVXNlcm5hbWUiOiJhZG1pbjEiLCJOaWNrTmFtZSI6ImFkbWluMSIsIkF1dGhvcml0eUlkIjoiYWRtaW4iLCJCdWZmZXJUaW1lIjo4NjQwMCwiZXhwIjo0ODEzMjY3NjM3LCJpc3MiOiJ2am1hcCIsIm5iZiI6MTY1OTY2NjYzN30.cDXCH2ElTzU2sQU36SNHWoTYTAc4wEkVIXmBAIzWh6M",
        exampleMapId: "sys_zp",
        assetsPath: "../../assets/",
        ...__env__ // 如果您已私有化部署，需要连接已部署的服务器地址和token，请打开js/env.js,修改里面的参数
    };
    try {
        // 在线效果查看地址: https://vjmap.com/map3d/demo/#/demo/map/threejs/129threeWebglhadowmap
        // --shadowmap--
        // 下面代码参考threejs官方示例改写 https://threejs.org/examples/#webgl_shadowmap
        let svc = new vjmap3d.Service(env.serviceUrl, env.accessToken);
        let app = new vjmap3d.App(svc, {
            container: "map", // 容器id
            scene: {
                background: 0x59472b,
                defaultLights: false
            },
            camera: {
                fov: 23,
                near: 10,
                far: 3000,
                position: [ 700, 50, 1900  ]
            }
        })
        let scene = app.scene, camera = app.camera, renderer = app.renderer;
        
        const SHADOW_MAP_WIDTH = 2048, SHADOW_MAP_HEIGHT = 1024;
        
        let SCREEN_WIDTH = app.containerSize.width;
        let SCREEN_HEIGHT = app.containerSize.height;
        const FLOOR = - 250;
        
        
        let mixer;
        
        const morphs = [];
        
        let light;
        let lightShadowMapViewer;
        
        
        let showHUD = false;
        
        init();
        
        function init() {
        
            scene.fog = new THREE.Fog( 0x59472b, 1000, 3000 );
        
            // LIGHTS
        
            const ambient = new THREE.AmbientLight( 0xffffff );
            scene.add( ambient );
        
            light = new THREE.DirectionalLight( 0xffffff, 3 );
            light.position.set( 0, 1500, 1000 );
            light.castShadow = true;
            light.shadow.camera.top = 2000;
            light.shadow.camera.bottom = - 2000;
            light.shadow.camera.left = - 2000;
            light.shadow.camera.right = 2000;
            light.shadow.camera.near = 1200;
            light.shadow.camera.far = 2500;
            light.shadow.bias = 0.0001;
        
            light.shadow.mapSize.width = SHADOW_MAP_WIDTH;
            light.shadow.mapSize.height = SHADOW_MAP_HEIGHT;
        
            scene.add( light );
        
            createHUD();
            createScene();
        
            // RENDERER
        
            renderer.autoClear = false;
        
            //
        
            renderer.shadowMap.enabled = true;
            renderer.shadowMap.type = THREE.PCFShadowMap;
        
        
            app.signal.onKeyDown.add(e => {
                let code = vjmap3d.eventKeyCode(e);
                switch (code ) {
        
                    case 84:	/*t*/
                        showHUD = ! showHUD;
                        break;
            
                }
            })
            app.signal.onAppUpdate.add(render);
            app.signal.onAppAfterRender.add(() => {
                if ( showHUD ) {
        
                    lightShadowMapViewer.render( renderer );
            
                }
            })
        }
        
        
        function createHUD() {
        
            lightShadowMapViewer = new ShadowMapViewer( light );
            lightShadowMapViewer.position.x = 10;
            lightShadowMapViewer.position.y = SCREEN_HEIGHT - ( SHADOW_MAP_HEIGHT / 4 ) - 10;
            lightShadowMapViewer.size.width = SHADOW_MAP_WIDTH / 4;
            lightShadowMapViewer.size.height = SHADOW_MAP_HEIGHT / 4;
            lightShadowMapViewer.update();
        
        }
        
        function createScene( ) {
        
            // GROUND
        
            const geometry = new THREE.PlaneGeometry( 100, 100 );
            const planeMaterial = new THREE.MeshPhongMaterial( { color: 0xffdd99 } );
        
            const ground = new THREE.Mesh( geometry, planeMaterial );
        
            ground.position.set( 0, FLOOR, 0 );
            ground.rotation.x = - Math.PI / 2;
            ground.scale.set( 100, 100, 100 );
        
            ground.castShadow = false;
            ground.receiveShadow = true;
        
            scene.add( ground );
        
            // TEXT
            let assetsPath = "https://vjmap.com/map3d/resources/three/"
            const loader = new FontLoader();
            loader.load(assetsPath + 'fonts/helvetiker_bold.typeface.json', function ( font ) {
        
                const textGeo = new TextGeometry( 'THREE.JS', {
        
                    font: font,
        
                    size: 200,
                    depth: 50,
                    curveSegments: 12,
        
                    bevelThickness: 2,
                    bevelSize: 5,
                    bevelEnabled: true
        
                } );
        
                textGeo.computeBoundingBox();
                const centerOffset = - 0.5 * ( textGeo.boundingBox.max.x - textGeo.boundingBox.min.x );
        
                const textMaterial = new THREE.MeshPhongMaterial( { color: 0xff0000, specular: 0xffffff } );
        
                const mesh = new THREE.Mesh( textGeo, textMaterial );
                mesh.position.x = centerOffset;
                mesh.position.y = FLOOR + 67;
        
                mesh.castShadow = true;
                mesh.receiveShadow = true;
        
                scene.add( mesh );
        
            } );
        
            // CUBES
        
            const cubes1 = new THREE.Mesh( new THREE.BoxGeometry( 1500, 220, 150 ), planeMaterial );
        
            cubes1.position.y = FLOOR - 50;
            cubes1.position.z = 20;
        
            cubes1.castShadow = true;
            cubes1.receiveShadow = true;
        
            scene.add( cubes1 );
        
            const cubes2 = new THREE.Mesh( new THREE.BoxGeometry( 1600, 170, 250 ), planeMaterial );
        
            cubes2.position.y = FLOOR - 50;
            cubes2.position.z = 20;
        
            cubes2.castShadow = true;
            cubes2.receiveShadow = true;
        
            scene.add( cubes2 );
        
            // MORPHS
        
            mixer = new THREE.AnimationMixer( scene );
        
            function addMorph( mesh, clip, speed, duration, x, y, z, fudgeColor ) {
        
                mesh = mesh.clone();
                mesh.material = mesh.material.clone();
        
                if ( fudgeColor ) {
        
                    mesh.material.color.offsetHSL( 0, Math.random() * 0.5 - 0.25, Math.random() * 0.5 - 0.25 );
        
                }
        
                mesh.speed = speed;
        
                mixer.clipAction( clip, mesh ).
                    setDuration( duration ).
                // to shift the playback out of phase:
                    startAt( - duration * Math.random() ).
                    play();
        
                mesh.position.set( x, y, z );
                mesh.rotation.y = Math.PI / 2;
        
                mesh.castShadow = true;
                mesh.receiveShadow = true;
        
                scene.add( mesh );
        
                morphs.push( mesh );
        
            }
        
            const gltfloader = new GLTFLoader();
        
            gltfloader.load(assetsPath + 'models/gltf/Horse.glb', function ( gltf ) {
        
                const mesh = gltf.scene.children[ 0 ];
        
                const clip = gltf.animations[ 0 ];
        
                addMorph( mesh, clip, 550, 1, 100 - Math.random() * 1000, FLOOR, 300, true );
                addMorph( mesh, clip, 550, 1, 100 - Math.random() * 1000, FLOOR, 450, true );
                addMorph( mesh, clip, 550, 1, 100 - Math.random() * 1000, FLOOR, 600, true );
        
                addMorph( mesh, clip, 550, 1, 100 - Math.random() * 1000, FLOOR, - 300, true );
                addMorph( mesh, clip, 550, 1, 100 - Math.random() * 1000, FLOOR, - 450, true );
                addMorph( mesh, clip, 550, 1, 100 - Math.random() * 1000, FLOOR, - 600, true );
        
            } );
        
            gltfloader.load(assetsPath + 'models/gltf/Flamingo.glb', function ( gltf ) {
        
                const mesh = gltf.scene.children[ 0 ];
                const clip = gltf.animations[ 0 ];
        
                addMorph( mesh, clip, 500, 1, 500 - Math.random() * 500, FLOOR + 350, 40 );
        
            } );
        
            gltfloader.load(assetsPath + 'models/gltf/Stork.glb', function ( gltf ) {
        
                const mesh = gltf.scene.children[ 0 ];
                const clip = gltf.animations[ 0 ];
        
                addMorph( mesh, clip, 350, 1, 500 - Math.random() * 500, FLOOR + 350, 340 );
        
            } );
        
            gltfloader.load(assetsPath + 'models/gltf/Parrot.glb', function ( gltf ) {
        
                const mesh = gltf.scene.children[ 0 ];
                const clip = gltf.animations[ 0 ];
        
                addMorph( mesh, clip, 450, 0.5, 500 - Math.random() * 500, FLOOR + 300, 700 );
        
            } );
        
        }
        
        
        function render(e) {
        
            const delta = e.deltaTime;
        
            mixer.update( delta );
        
            for ( let i = 0; i < morphs.length; i ++ ) {
        
                const morph = morphs[ i ];
        
                morph.position.x += morph.speed * delta;
        
                if ( morph.position.x > 2000 ) {
        
                    morph.position.x = - 1000 - Math.random() * 500;
        
                }
        
            }
        
        
        }
        
        
        
        
        
        
        
        
        
        
    }
    catch (e) {
        console.error(e);
    }
};